package com.googlecode.tidej.client.editor;

import java.util.ArrayList;

import com.google.gwt.dom.client.Style;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.SplitLayoutPanel;
import com.google.gwt.user.client.ui.SuggestBox;
import com.googlecode.tidej.client.TidejController;
import com.googlecode.tidej.shared.model.Operation;
import com.googlecode.tidej.shared.model.Parameter;
import com.googlecode.tidej.shared.model.Type;


public class OperationDetailWidget extends Composite {
  SplitLayoutPanel splitPanel = new SplitLayoutPanel(20);
  SuggestList suggestList;
  FlowPanel mainPanel = new FlowPanel();
  ScrollPanel scrollPanel = new ScrollPanel(mainPanel);
  DocumentationEditor textArea = new DocumentationEditor();
  FlexTable table = new FlexTable();
  ArrayList<ParameterDetails> parameterDetailList = 
      new ArrayList<ParameterDetails>();
  Operation operation;
  FlowPanel parameterPanel = new FlowPanel();
  FlowPanel implementationPanel = new FlowPanel();
  CodeEditor codeEditor;
  Button modifySignatureButton = new Button("Modify signature");
  boolean readOnly;
  TidejController controller;
  ArtifactEditor owner;
  HTML title = new HTML();
  
  OperationDetailWidget(final ArtifactEditor owner) {
    this.owner = owner;
    this.controller = owner.controller;
    suggestList = new SuggestList(controller.getModel());
    
    splitPanel.addEast(suggestList, 200);
    splitPanel.add(scrollPanel);
    
    table.addStyleName("property-table");
    mainPanel.getElement().getStyle().setProperty("padding", "0 10px");
    mainPanel.add(title);
    mainPanel.add(textArea);
    textArea.setWidth("100%");
    
    parameterPanel.add(new HTML("<p><b>Parameters</b></p>"));
    parameterPanel.add(table);

    mainPanel.add(parameterPanel);
    
    modifySignatureButton.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event) {
        owner.save();
        new OperationSignatureDialog(controller).editOperation(operation);
      }
    });
    mainPanel.add(modifySignatureButton);
    
//    mainPanel.add(new Label("\u00a0"));
    implementationPanel.add(new HTML("<p><b>Implementation</b></p>"));
    codeEditor = new CodeEditor(controller, suggestList);
    implementationPanel.add(codeEditor);
    mainPanel.add(implementationPanel);
    initWidget(splitPanel);
  }
  
  public void setOperation(Operation o) {
    this.operation = o;
    readOnly = o.getLibrary().isReadOnly();
    
  //  editButton.setVisible(!readOnly);
   
    implementationPanel.setVisible(!readOnly);
    suggestList.setVisible(!readOnly);
//    if (readOnly) {
      splitPanel.setWidgetSize(suggestList, readOnly ? -20 : 200);
  //  }
    
    if (o != null) {
      String name = o.getName();
      if (name.startsWith("(")) {
        title.setHTML("<p><b>Global Documentation</b></p>");
        modifySignatureButton.setVisible(false);
      } else {
        modifySignatureButton.setVisible(!readOnly);
        if (o.getName().equals(o.getOwner().getName())) {
          title.setHTML("<p><b>Class and Constructor Documentation</b></p>");
        } else {
          title.setHTML("<p><b>Method Documentation</b></p>");
        }
      }
      
      if (readOnly) {
        table.addStyleName("readonly");
      } else {
        table.removeStyleName("readonly");
      }
      
      textArea.setArtifactAndResize(o, readOnly);
      codeEditor.setOperation(o);

      table.removeAllRows();
      parameterDetailList.clear();

      if (o.getParameters().size() == 0 && o.getType() == null) {
        parameterPanel.setVisible(false);
        return;
      }
      parameterPanel.setVisible(true);
      
      table.setHTML(0, 0, "<b>Name</b>");
      table.setHTML(0, 1, "<b>Type</b>");
      table.setHTML(0, 2, "<b>Documentation</b>");
      table.setWidth("100%");

      for (Parameter p: o.getParameters()) {
        ParameterDetails details = new ParameterDetails(p);
        parameterDetailList.add(details);
      }
    }
  }
  
  public boolean checkModifications() {
    if (operation == null) {
      return false;
    }
    // No short-circuiting here and below: side effects required.
    boolean result = textArea.checkModifications() | 
        codeEditor.checkModifications();
    for (ParameterDetails p: parameterDetailList) {
      if (p.checkModifications()) {
        result = true;
      }
    }
    return result;
  }
  
  
  class ParameterDetails {
    Parameter parameter;
    DocumentationEditor documentationEditor = new DocumentationEditor();
    SuggestBox typeBox;
    
    ParameterDetails(final Parameter parameter) {
      this.parameter = parameter;
      documentationEditor.setArtifactAndResize(parameter, readOnly);
      
      final int row = table.getRowCount();
      

      if (readOnly) {
        table.setHTML(row, 0, "<b>" + parameter.getName() + "</b>");
        table.setText(row, 1, parameter.getType() == null ? "*" : parameter.getType().getName());
      } else {
        Label label = new Label(parameter.getName());
        Style style = label.getElement().getStyle();
        style.setProperty("padding", "8px 2px");
        style.setProperty("fontWeight", "bold");
        table.setWidget(row, 0, label);
        typeBox = new SuggestBox(controller.getTypeSuggestOracle());
        if (parameter.getType() != null) {
          typeBox.setValue(parameter.getType().toString());
        }
        table.setWidget(row, 1, typeBox);
      }
      table.setWidget(row, 2, documentationEditor);
      documentationEditor.getElement().getParentElement().setAttribute("width", "99%");
    }
  
    boolean checkModifications() {
      if (readOnly) {
        return false;
      }
    
      boolean modified = false;
      String newTypeName = typeBox.getText();
      if (newTypeName != null && newTypeName.length() > 0) {
        Type newType = controller.getModel().getType(newTypeName);
        if (newType != null && !newType.equals(parameter.getType())) {
          modified = true;
          parameter.setType(newType);
        }
      }
      
      if (documentationEditor.checkModifications()) {
        modified = true;
      }
      return modified;
    }
  }
  
  
}
